import * as fs from 'fs';
import * as path from 'path';
import { OpenAI } from 'openai';
import axios from 'axios';
import { uploadMdToFeishu } from './uploadFs';
import { FeishuResponse } from './types';
import { spawn } from 'child_process';

// 初始化OpenAI客户端
const client = new OpenAI({
  apiKey: "sk-G0B349tTLMNwzNo0ClA4neWCvZF06uemnEuXaMkiZsiPb2ef",
  baseURL: "https://api.chatfire.cn/v1"  // 允许自定义API基础URL
});

// 飞书配置
const FEISHU_APP_ID = "cli_a750f1d07210d00d";
const FEISHU_APP_SECRET = "KDcAVmk8LhuKc1sQQPEK2baus6PDRQpN";
const FEISHU_WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/your-webhook-url";  // 需要替换为实际的webhook URL

// 视频处理配置
const MAX_API_SIZE_MB = 100;       // API理论最大上传大小(MB)（大多数模型支持100MB）
const SAFE_API_SIZE_MB = 75;       // 较为安全的API限制(MB)，避免接近上限
const FALLBACK_SIZE_MB = 20;       // 无FFmpeg时的最大尺寸

// 提示词
const prompt = `
系统提示:
你是一位专业的小程序需求分析师，擅长从视频演示中提取UI组件、功能流程和业务逻辑。请分析提供的微信小程序操作视频，生成结构化需求文档。

用户提示:
我正在分析一个竞品微信小程序的视频演示。请基于此视频：
1. 识别所有页面和关键UI组件
2. 梳理完整的功能流程图
3. 提取核心业务逻辑
4. 生成标准化的需求清单
5. 标注出可能的技术实现方式
6. 总结出该项目的名称，"项目名称：xxx"

分析要求:
- 将需求分为"必要功能"和"增强功能"
- 标注每个功能的复杂度(低/中/高)
- 指出依赖外部服务的功能(如支付、地图、消息推送)
- 提供数据结构建议
`;

/**
 * 检查FFmpeg是否可用
 * @returns 是否可用
 */
async function isFFmpegAvailable(): Promise<boolean> {
  return new Promise((resolve) => {
    try {
      const ffmpeg = spawn('ffmpeg', ['-version']);
      
      ffmpeg.on('error', () => {
        console.warn('未检测到FFmpeg');
        resolve(false);
      });
      
      ffmpeg.on('close', (code) => {
        if (code === 0) {
          console.log('FFmpeg已安装并可用');
          resolve(true);
        } else {
          console.warn(`FFmpeg检查失败，退出代码: ${code}`);
          resolve(false);
        }
      });
    } catch (error) {
      console.warn('FFmpeg检测过程出错');
      resolve(false);
    }
  });
}

/**
 * 使用FFmpeg压缩视频文件
 * @param inputPath 输入视频路径
 * @param maxSizeMB 最大尺寸（MB）
 * @returns 压缩后的视频路径
 */
async function compressVideo(inputPath: string, maxSizeMB: number = SAFE_API_SIZE_MB): Promise<string> {
  const outputPath = `${inputPath.replace(/\.\w+$/, '')}_compressed.mp4`;
  
  // 首先检查FFmpeg是否可用
  const ffmpegAvailable = await isFFmpegAvailable();
  if (!ffmpegAvailable) {
    console.warn('FFmpeg不可用，无法压缩视频，尝试使用替代方案');
    return inputPath; // 如果FFmpeg不可用，返回原始路径
  }
  
  return new Promise((resolve, reject) => {
    console.log(`开始压缩视频: ${inputPath} -> ${outputPath}`);
    
    // 使用FFmpeg压缩视频
    const ffmpeg = spawn('ffmpeg', [
      '-i', inputPath,
      '-vcodec', 'libx264',
      '-crf', '28',  // 控制质量，值越高压缩率越高，23-28是好的平衡点
      '-preset', 'medium',  // 压缩速度和质量的平衡
      '-movflags', '+faststart',
      '-y',  // 覆盖已存在的文件
      outputPath
    ]);
    
    ffmpeg.stderr.on('data', (data) => {
      // FFmpeg进度信息输出到stderr
      console.log(`FFmpeg: ${data.toString()}`);
    });
    
    ffmpeg.on('error', (err) => {
      console.error(`FFmpeg错误: ${err.message}`);
      resolve(inputPath); // 出错时使用原始视频
    });
    
    ffmpeg.on('close', (code) => {
      if (code === 0) {
        // 检查压缩后的文件大小
        const stats = fs.statSync(outputPath);
        const fileSizeMB = stats.size / (1024 * 1024);
        console.log(`视频压缩完成，大小: ${fileSizeMB.toFixed(2)}MB`);
        
        // 如果压缩后还是太大，再次压缩
        if (fileSizeMB > maxSizeMB) {
          console.log(`压缩后的视频仍然太大(${fileSizeMB.toFixed(2)}MB > ${maxSizeMB}MB)，将提取关键帧`);
          // 提取视频的关键片段或降低分辨率
          const recompressPath = `${inputPath.replace(/\.\w+$/, '')}_final.mp4`;
          
          const recompress = spawn('ffmpeg', [
            '-i', outputPath,
            '-vf', 'scale=640:-1',  // 降低分辨率到640p
            '-r', '15',  // 降低帧率到15fps
            '-crf', '32',  // 更高的压缩率
            '-preset', 'ultrafast',
            '-y',
            recompressPath
          ]);
          
          recompress.on('error', (err) => {
            console.error(`二次压缩错误: ${err.message}`);
            resolve(outputPath); // 出错时使用一次压缩的结果
          });
          
          recompress.on('close', (reCode) => {
            if (reCode === 0) {
              console.log(`二次压缩完成，路径: ${recompressPath}`);
              resolve(recompressPath);
            } else {
              console.warn(`二次压缩失败，使用第一次压缩的结果`);
              resolve(outputPath);
            }
          });
        } else {
          resolve(outputPath);
        }
      } else {
        console.error(`视频压缩失败，错误代码: ${code}`);
        resolve(inputPath);  // 失败时使用原始视频
      }
    });
  });
}

/**
 * 不使用FFmpeg的情况下处理大视频（分段提取帧）
 * @param videoPath 视频文件路径
 * @returns 处理后用于分析的图像路径数组
 */
async function processLargeVideoWithoutFFmpeg(videoPath: string): Promise<string[]> {
  // 创建临时目录存放提取的帧
  const framesDir = `${path.dirname(videoPath)}/frames_${path.basename(videoPath, path.extname(videoPath))}`;
  if (!fs.existsSync(framesDir)) {
    fs.mkdirSync(framesDir, { recursive: true });
  }
  
  console.log(`无法使用FFmpeg，将采用分段处理策略。创建帧目录: ${framesDir}`);
  
  try {
    // 这里我们将直接提取视频开头、中间和结尾的部分进行分析
    // 实际上这需要前端支持，因为Node.js本身不容易处理视频帧
    // 这里只是一个示例，实际项目中可能需要使用浏览器或其他工具
    
    // 创建说明文件
    const readmePath = path.join(framesDir, 'README.txt');
    fs.writeFileSync(readmePath, `
无法压缩视频（FFmpeg未安装）。
为了处理，请考虑以下替代方案：
1. 手动安装FFmpeg
2. 使用较小的视频文件（小于${SAFE_API_SIZE_MB}MB）
3. 使用视频编辑软件提取关键片段

当前视频文件: ${videoPath}
大小: ${(fs.statSync(videoPath).size / (1024 * 1024)).toFixed(2)}MB
    `);
    
    console.log(`由于无法处理大视频，已创建说明文件: ${readmePath}`);
    
    // 返回说明文件作为替代
    return [readmePath];
  } catch (error) {
    console.error(`处理大视频时出错: ${(error as Error).message}`);
    return [];
  }
}

/**
 * 生成无法处理视频时的错误报告
 * @param videoPath 视频文件路径
 * @param fileSizeMB 视频大小(MB)
 * @param reason 失败原因
 * @returns 错误报告
 */
function generateVideoProcessingFailureReport(videoPath: string, fileSizeMB: number, reason: string): string {
  const videoName = path.basename(videoPath);
  const timestamp = new Date().toISOString().replace(/[:.]/g, '_');
  
  return `
# 视频分析失败 - 需要额外处理_${timestamp}

## 视频分析失败报告

**文件信息:**
- 路径: ${videoName}
- 大小: ${fileSizeMB.toFixed(2)}MB

**失败原因:** ${reason}

**解决方案建议:**
1. 安装FFmpeg (https://ffmpeg.org/download.html)
2. 使用较小的视频文件 (建议小于${FALLBACK_SIZE_MB}MB)
3. 手动分割视频为多个片段进行分析
4. 使用视频编辑软件提取关键片段

项目名称：视频分析失败 - 需要额外处理
`;
}

/**
 * 处理视频文件
 * @param videoPath 视频文件路径
 * @param promptText 提示词
 * @returns 分析结果或null
 */
async function processVideo(videoPath: string, promptText: string): Promise<string | null> {
  try {
    // 检查文件是否存在
    if (!fs.existsSync(videoPath)) {
      throw new Error(`视频文件不存在: ${videoPath}`);
    }
    
    // 检查文件大小
    const fileStats = fs.statSync(videoPath);
    const fileSizeMB = fileStats.size / (1024 * 1024);
    console.log(`原始视频大小: ${fileSizeMB.toFixed(2)}MB`);
    
    // 如果视频超过限制
    let processedVideoPath = videoPath;
    let framePaths: string[] = [];
    let skipAPICall = false;
    
    // 检查FFmpeg是否可用
    const ffmpegAvailable = await isFFmpegAvailable();
    console.log(`FFmpeg状态: ${ffmpegAvailable ? '可用' : '不可用'}`);
    
    // 确定当前环境下的大小限制
    const currentSizeLimit = ffmpegAvailable ? SAFE_API_SIZE_MB : FALLBACK_SIZE_MB;
    
    // 如果视频大小超过当前环境的限制
    if (fileSizeMB > currentSizeLimit) {
      console.log(`视频文件大小(${fileSizeMB.toFixed(2)}MB)超过当前环境限制(${currentSizeLimit}MB)，尝试处理`);
      
      if (ffmpegAvailable) {
        // 使用FFmpeg压缩
        processedVideoPath = await compressVideo(videoPath, currentSizeLimit);
        const compressedStats = fs.statSync(processedVideoPath);
        const compressedSizeMB = compressedStats.size / (1024 * 1024);
        
        // 如果压缩后仍然太大
        if (compressedSizeMB > currentSizeLimit) {
          console.warn(`即使经过最大压缩，视频仍然太大 (${compressedSizeMB.toFixed(2)}MB > ${currentSizeLimit}MB)`);
          skipAPICall = true;
          return generateVideoProcessingFailureReport(
            videoPath, 
            fileSizeMB, 
            `即使使用FFmpeg最大压缩后仍然超过限制 (${compressedSizeMB.toFixed(2)}MB > ${currentSizeLimit}MB)`
          );
        }
        
        console.log(`使用压缩后的视频: ${processedVideoPath}, 大小: ${compressedSizeMB.toFixed(2)}MB`);
      } else {
        // 如果没有FFmpeg，无法压缩大视频，直接返回错误报告
        console.log(`视频太大且无FFmpeg可用(${fileSizeMB.toFixed(2)}MB > ${currentSizeLimit}MB)，无法处理`);
        skipAPICall = true;
        return generateVideoProcessingFailureReport(
          videoPath, 
          fileSizeMB, 
          `系统中未安装FFmpeg，无法压缩视频文件(${fileSizeMB.toFixed(2)}MB)`
        );
      }
    }
    
    // 如果设置了跳过API调用或视频过大，直接返回
    if (skipAPICall) {
      return generateVideoProcessingFailureReport(
        videoPath, 
        fileSizeMB, 
        "视频无法处理，跳过API调用"
      );
    }
    
    // 检查处理后的文件大小
    const processedStats = fs.statSync(processedVideoPath);
    const processedSizeMB = processedStats.size / (1024 * 1024);
    
    // 安全检查：如果处理后仍然太大，超过API绝对限制，拒绝发送请求
    if (processedSizeMB > MAX_API_SIZE_MB) {
      console.error(`处理后视频仍然过大(${processedSizeMB.toFixed(2)}MB)，超出API最大限制(${MAX_API_SIZE_MB}MB)，拒绝发送请求`);
      return generateVideoProcessingFailureReport(
        videoPath, 
        fileSizeMB, 
        `处理后仍然超出API最大限制 (${processedSizeMB.toFixed(2)}MB > ${MAX_API_SIZE_MB}MB)`
      );
    }
    
    // 警告
    if (processedSizeMB > SAFE_API_SIZE_MB) {
      console.warn(`处理后视频接近API限制(${processedSizeMB.toFixed(2)}MB > ${SAFE_API_SIZE_MB}MB)，可能导致请求失败`);
    }
    
    console.log(`开始分析视频，文件大小: ${processedStats.size} 字节 (${processedSizeMB.toFixed(2)}MB)`);
    
    // 读取视频文件
    const videoFile = fs.readFileSync(processedVideoPath);
    const base64Video = videoFile.toString('base64');
    
    // 创建请求
    const response = await client.chat.completions.create({
      model: "gemini-2.0-flash",  // 使用支持视觉功能的模型
      messages: [
        {
          role: "user",
          content: [
            { type: "text", text: promptText },
            {
              type: "image_url",
              image_url: {
                url: `data:video/mp4;base64,${base64Video}`
              }
            }
          ]
        }
      ],
      max_tokens: 4000
    });
    
    // 检查响应
    if (!response || !response.choices || response.choices.length === 0) {
      console.error("AI返回空响应或格式异常");
      return null;
    }
    
    // 获取结果
    const result = response.choices[0].message.content;
    if (!result) {
      console.error("AI返回内容为空");
      return null;
    }
    
    // 确保结果包含项目名称
    if (!result.includes("项目名称：")) {
      console.log("AI返回结果中未找到项目名称，添加默认名称");
      const analysisResult = `项目名称：微信小程序分析\n\n${result}`;
      console.log(`完整分析结果长度: ${analysisResult.length}`);
      return analysisResult;
    }
    
    console.log(`完整分析结果长度: ${result.length}`);
    return result;
  } catch (error) {
    console.error(`处理视频时发生错误: ${(error as Error).message}`);
    console.error(`错误堆栈: ${(error as Error).stack}`);
    
    // 如果是413错误，返回特定错误提示
    const errorMessage = (error as Error).message || '';
    if (errorMessage.includes('413') || errorMessage.includes('Request Entity Too Large')) {
      return generateVideoProcessingFailureReport(
        videoPath, 
        fs.statSync(videoPath).size / (1024 * 1024), 
        "API请求实体过大 (HTTP 413 错误)，视频文件超出API服务器接受的大小限制"
      );
    }
    
    return null;
  }
}

/**
 * 获取飞书租户访问令牌
 * @returns 访问令牌或null
 */
async function getFeishuTenantAccessToken(): Promise<string | null> {
  try {
    const url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
    const headers = {
      "Content-Type": "application/json"
    };
    const data = {
      app_id: FEISHU_APP_ID,
      app_secret: FEISHU_APP_SECRET
    };
    
    const response = await axios.post<FeishuResponse>(url, data, { headers });
    console.log(`获取令牌响应: ${JSON.stringify(response.data)}`);
    
    if (response.data.code === 0) {
      // return response.data.data?.tenant_access_token || null;
      return "u-fbyW2F8nt4JVyGDtz8wvy3ll4LXgl5tHrgw0h0kGyECD";
    } else {
      console.error(`获取租户访问令牌失败: ${JSON.stringify(response.data)}`);
      return null;
    }
  } catch (error) {
    console.error(`获取租户访问令牌时发生错误: ${(error as Error).message}`);
    return null;
  }
}


// 导出模块
export {
  processVideo,
  prompt,
  getFeishuTenantAccessToken,
  compressVideo,
  isFFmpegAvailable
}; 